#include "SZNR/SZNR103Constructer.h"
#include <QDebug>
#include "utils.h"

SZNR103Constructer::SZNR103Constructer()
{

}

SZNR103Constructer::~SZNR103Constructer()
{

}

QByteArray SZNR103Constructer::getVariableFrame(QByteArray& asdu, QByteArray& addr, int funCodeIndex)
{
    QByteArray  frame;
    uint len = asdu.count()/2 + 2;
    QByteArray lenBytes =  Utils::intToHexByte(len);

    QByteArray code = constructCode(funCodeIndex);

    // 计算校验和
    QByteArray tmpBytes;
    tmpBytes.push_back(addr);
    tmpBytes.push_back(code);
    tmpBytes.push_back(asdu);
    QByteArray cs = SZNR103Constructer::sumcheck(tmpBytes);

//    QByteArray m_cs = Utils::intToHexByte(cs);

    frame.push_back(APCI_START);
    frame.push_back(lenBytes);
    frame.push_back(lenBytes);
    frame.push_back(APCI_START);
    frame.push_back(code);
    frame.push_back(addr);
    frame.push_back(asdu);
    frame.push_back(cs);
    frame.push_back(END_FLAG);

    return frame;
}

// 复位计数帧计数位
QByteArray SZNR103Constructer::constructRFB(QByteArray addr)
{
    QByteArray ret;
    ret.push_back("1047");
    ret.push_back(addr);
    ret.push_back(SumCheck("47"+addr));
    ret.push_back("16");

    return ret;
}

QByteArray SZNR103Constructer::constructRCU(QByteArray addr)
{
    QByteArray ret;
    ret.push_back("1040");
    ret.push_back(addr);

    QByteArray cs = sumcheck(ret.mid(2, 4));    // 取地址域控制域计算校验和，溢出位不管
    qDebug() << "校验和 = " << cs;
    ret.push_back( cs );
    ret.push_back("16");

    return ret;
}

QByteArray SZNR103Constructer::constructPL2(QByteArray &addr, QByteArray &code)
{
    QByteArray ret;
    ret.push_back("10" + code + addr);
    ret.push_back(SumCheck("40" + addr));
    ret.push_back("16");

    return ret;
}

QByteArray SZNR103Constructer::constructRLK(QByteArray &addr, QByteArray &code)
{
    QByteArray ret;

    ret.push_back("10" + code + addr);
    ret.push_back(SumCheck("40" + addr));
    ret.push_back("16");

    return ret;
}

QByteArray SZNR103Constructer::constructPL1(QByteArray &addr)
{
    QByteArray ret;     // 10 5A(控制) 01(地址) 5B 16
    QByteArray cs;
    if(m_fcb == false) {
        ret.push_back("105a" + addr); // 控制域，在召唤1级数据时候 固定以"5A" 和 "5B" 轮回
        cs = sumcheck(ret.mid(2, 4));
        m_fcb = true;
    }
    else {
        ret.push_back("107a" + addr);
        cs = sumcheck(ret.mid(2, 4));
        m_fcb = false;
    }
    ret.push_back(cs);
    ret.push_back("16");
    return ret;
}

QByteArray SZNR103Constructer::constructCode(int funCodeIndex)
{
    QByteArray codebin = "01000000";        // 第7个位 PRM 始终为 1 ，表示由控制系统向继电保护设备进行传输

    // 功能码 0~3
    // 1. 发送/确认帧 ，复位通信单元 功能序号=0, fcv=0

    // 功能码序号=3， fcv=1, code = "1100 1000"
    switch (funCodeIndex) {
    case 0:
            // fcv = 0  复位通信单元
            break;
    case 3:                     // 传输数据（读全部组标题，读指定组名称等）
        codebin[4] = '1';   // fcv = 1
        codebin[7] = '1';
        break;
    case 4:             // fcv =0;
        codebin[3] = '1';
        break;
    case 7:
        codebin[7] = '1';
        codebin[6] = '1';
        codebin[5] = '1';
        break;
    case 9:
        codebin[0] = '1';
        codebin[3] = '1';
        break;
    case 10:
        codebin[4] ='1';
        codebin[3] = '1';
        codebin[1] = '1';
        break;
    case 12:
        break;
    case 13:
        break;
    default:
        break;
    }

    qDebug() << "code = " << codebin;
    // 转换成 16进制
    codebin = Utils::binStrToHexStr(codebin);
    qDebug() << "code = " << codebin;
    return codebin;
}

QByteArray SZNR103Constructer::constructReadTitles(QString &addr)
{
    ASDUStruct  asduReadTitle =  m_asduConstructer->constructReadAllTitles(addr);
    QString asdu = asduReadTitle.asduToQString();
    QByteArray asduByteArray = asdu.toLatin1();

    QByteArray addrByte = addr.toLatin1();
    QByteArray ret =  getVariableFrame(asduByteArray, addrByte, 3);

    return ret;
}

QByteArray SZNR103Constructer::constructGetBillInfo(QString &addr, QString& groupNo, QString& kod)
{
    ASDUStruct asduReadBillInfo =  m_asduConstructer->constructGetBillValueData(addr, groupNo, kod);
    QByteArray asduByteArray = asduReadBillInfo.asduToBytes();
    QByteArray addrByte = addr.toLatin1();
    QByteArray  ret = getVariableFrame(asduByteArray, addrByte, 3);

    return  ret;
}

uint8_t SZNR103Constructer::SumCheck(const QString &packet, int32_t length)
{
    QByteArray packetByteArray = packet.toLatin1();
    const char* pack = packetByteArray;
    uint8_t result = 0;
    for( int32_t i = 0; i < length; i++ )
    {
        result += pack[i];
    }

    return result;
}

uint8_t SZNR103Constructer::LenCal(const QByteArray &packet)
{
    int asduLen = packet.count()/2;
    return  asduLen+2;
}

QByteArray SZNR103Constructer::changeCtrl(QByteArray &code)
{
    int u = code.toUShort(nullptr, 16);
    QByteArray codeNew = QString("%1").arg(u, 8, 2, QLatin1Char('0')).toLatin1();

    // 对计数取反
    if (codeNew.at(POS_CODE_FCB) == '1') {
        codeNew[POS_CODE_FCB] = '0';
    }
    else {
        codeNew[POS_CODE_FCB] = '1';
    }

    return codeNew;
}

uint8_t SZNR103Constructer::SumCheck(const QByteArray &packet)
{
    uint8_t result = 0;
    int length = packet.count();    // 地址域 + 控制域 + asdu
    for ( int32_t i = 0; i < length; i++ )
    {
        result += packet[i];

    }

    return result;
}

QByteArray SZNR103Constructer::sumcheck(const QByteArray &packet)
{
    QByteArray ret;
    unsigned int result = 0;
    int length = packet.count();    // 地址域 + 控制域 + asdu

    for (int i=0; i<length; i+=2) {
        int tmp = (packet.mid(i,2).toInt(nullptr, 16));
        result += tmp;
    }
    qDebug() << "和 =" << result;

    QByteArray tmpRet =  Utils::intToHexByte(result);

    qDebug() << "校验和 =  " << tmpRet;
    if (tmpRet.count() > 2) {           //  溢出位忽略
          tmpRet = tmpRet.mid(1, 2);
    }

    return  tmpRet;
}
